#pragma once

#include "rewine/IExport.hpp"

#include <list>
#include <map>
#include <string>

namespace rewine
{

class CCustomImage;
class IImage;
class Loader;
class PathResolver;
class SymbolResolver;

class LibEntry {
private:

    std::string m_ExportName;

    using list_t = std::list<std::shared_ptr<IImage>>;
    list_t m_Images;

    std::shared_ptr<CCustomImage> m_pPreferred;
    std::shared_ptr<CCustomImage> m_pFallback;

private:

    list_t::const_iterator find(IImage *pImage) const;
    list_t::iterator find(IImage *pImage);

public:

    LibEntry(const std::string& m_ExportName);
    ~LibEntry() = default;

public:

    const std::string& exportName() const {
        return m_ExportName;
    }

    // after NULL means add_first
    bool addAfter(IImage *pSentry, IImage *pImage);
    // before NULL means add_last
    bool addBefore(IImage *pSentry, IImage *pImage);

    int remove(IImage *pImage);
    int removeFailed();

    bool isEmpty() const;
    bool tryToEmpty();

    bool contains(IImage *pImage) const;
    IImage * getByFullname(const std::string& fullname) const;

    void setOverride(const std::string& symbolName, std::shared_ptr<IExport> spExport, bool bPrefer = true);
    void setOverride(const std::string& symbolName, IExport *pExport, bool bPrefer = true);
    void setOverrideForward(const std::string& symbolName, IExport *pForwarded, bool bPrefer = true);
    void unsetOverride(const std::string& symbolName, bool bPrefer = true);

    IExport * resolve(const std::string& symbolName, uint16_t hint, std::shared_ptr<IImage> *pspImage) const;

};

class LibManager {
private:

    using map_t = std::map<std::string_view, std::shared_ptr<LibEntry>>;
    map_t m_Libs;

private:

    int tryToCleanAll();

public:

    LibManager() = default;
    ~LibManager() = default;

public:

    LibEntry * get(const std::string& libName);
    bool tryToClean(const std::string& libName);

    LibEntry * getByFullname(const std::string& fullname, IImage **ppImage) const;

};

} // namespace rewine
